package com.mi.rule.db.dao;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.mi.rule.db.core.MiHelp;
import com.mi.rule.db.entity.MiEntity;
import com.mi.rule.db.mapper.MiMapper;
import com.mi.rule.db.core.MiWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 通用的查询实现类
 *
 * @author 王永吉
 */
@Service
public class MiDaoImpl implements MiDao {

    @Autowired
    private MiMapper miMapper2;

    @Override
    public <P extends MiEntity> long insert(P entity) {
        if (entity == null) return 0;
        return miMapper2._insert_by_entity_(MiHelp.getTableName(entity.getClass()), MiHelp.getNotNullColumn(entity), entity);
    }

    @Override
    public <P extends MiEntity> long insertBatch(List<P> entityList) {
        return insertBatch(entityList, 1000);
    }

    @Override
    public <P extends MiEntity> long insertBatch(List<P> entityList, int batchSize) {
        long addCount = 0;
        if (entityList.size() == 0) return 0;

        P p = entityList.get(0);
        String tableName = MiHelp.getTableName(p.getClass());
        HashMap<String, Object> notNullColumn = MiHelp.getNotNullColumn(p);

        int count = entityList.size() / batchSize;
        for (int i = 0; i < count; i++) {
            addCount += miMapper2._insert_batch_by_entity_(tableName, notNullColumn, entityList.subList(i * batchSize, (i + 1) * batchSize));
        }

        int yu = entityList.size() % batchSize;
        if (yu > 0) {
            addCount += miMapper2._insert_batch_by_entity_(tableName, notNullColumn, entityList.subList(count * batchSize, (count * batchSize) + yu));
        }

        return addCount;
    }

    @Override
    public <P extends MiEntity> long insertOrUpdate(P entity) {
        if (miMapper2._count_by_id_(MiHelp.getTableName(entity.getClass()), MiHelp.getTableId(entity), MiHelp.getIdValue(entity)) <= 0) {
            return insert(entity);
        }
        return updateById(entity);
    }

    @Override
    public <P extends MiEntity> long insertOrUpdate(P entity, MiWrapper<P> miWrapper) {
        if (miMapper2._count_by_wrapper_(miWrapper.getTableName(), miWrapper.getSqlJoin(), 1, miWrapper) <= 0) {
            return insert(entity);
        }
        return miMapper2._update_by_wrapper_(MiHelp.getTableName(entity), MiHelp.getNotNullColumn(entity), entity, miWrapper);
    }

    @Override
    public <P extends MiEntity> long insertOrUpdateBatch(List<P> entityList) {
        return insertOrUpdateBatch(entityList, 1000);
    }

    @Override
    public <P extends MiEntity> long insertOrUpdateBatch(List<P> listEntity, int batchSize) {
        if (listEntity.size() == 0) return 0;

        String tableName = MiHelp.getTableName(listEntity.get(0));
        String tableId = MiHelp.getTableId(listEntity.get(0));

        List<P> listAdd = new ArrayList<>();
        List<P> listUpdate = new ArrayList<>();
        for (P p : listEntity) {
            long count = miMapper2._count_by_id_(tableName, tableId, MiHelp.getIdValue(p));
            if (count <= 0) {
                listAdd.add(p);
            } else {
                listUpdate.add(p);
            }
        }

        long l = 0;
        if (listAdd.size() > 0) {
            l = insertBatch(listAdd, batchSize);
        }
        long l1 = updateBatchById(listUpdate, batchSize);
        return (l + l1);
    }

    @Override
    public <P extends MiEntity> long delete(MiWrapper<P> miWrapper) {
        return miMapper2._delete_by_wrapper_(miWrapper.getTableName(), miWrapper);
    }

    @Override
    public <P extends MiEntity> long deleteById(Class<P> pClass, Serializable id) {
        return miMapper2._delete_by_id_(MiHelp.getTableName(pClass), id);

    }

    @Override
    public <P extends MiEntity, MP extends Map<?, ?>> long deleteByMap(Class<P> pClass, MP columnMap) {
        return miMapper2._delete_by_map_(MiHelp.getTableName(pClass), columnMap);

    }

    @Override
    public <P extends MiEntity> long deleteByIds(Class<P> pClass, List<? extends Serializable> idList) {
        return miMapper2._delete_by_ids_(MiHelp.getTableName(pClass), idList);
    }

    @Override
    public <P extends MiEntity> long update(MiWrapper<P> miWrapper) {

        if (miWrapper.getSqlSet() == null) return 0;

        return miMapper2._update_by_wrapper_sql_set_(miWrapper.getTableName(), miWrapper.getSqlSet(), miWrapper);
    }

    @Override
    public <P extends MiEntity> long update(P entity, MiWrapper<P> miWrapper) {
        return miMapper2._update_by_wrapper_(MiHelp.getTableName(entity), MiHelp.getNotNullColumn(entity), entity, miWrapper);
    }

    @Override
    public <P extends MiEntity> long updateById(P entity) {
        return miMapper2._update_by_id_(MiHelp.getTableName(entity), MiHelp.getNotNullColumn(entity), entity, MiHelp.getTableId(entity), MiHelp.getIdValue(entity));
    }

    @Override
    public <P extends MiEntity> long updateBatchById(List<P> entityList) {
        return updateBatchById(entityList, 1000);
    }

    @Override
    public <P extends MiEntity> long updateBatchById(List<P> entityList, int batchSize) {
        long addCount = 0;

        if (entityList.size() == 0) return addCount;
        P p = entityList.get(0);
        String tableName = MiHelp.getTableName(p);

        int count = entityList.size() / batchSize;
        for (int i = 0; i < count; i++) {
            addCount += miMapper2._update_batch_by_id_(tableName, MiHelp.getNotNullColumn(p), entityList.subList(i * batchSize, (i + 1) * batchSize));
        }

        int yu = entityList.size() % batchSize;
        if (yu > 0) {
            addCount += miMapper2._update_batch_by_id_(tableName, MiHelp.getNotNullColumn(p), entityList.subList(count * batchSize, (count * batchSize) + yu));
        }

        return addCount;
    }

    @Override
    public <P extends MiEntity> P selectById(Class<P> pClass, Serializable id) {
        Map<?, ?> map = miMapper2._select_by_id_(MiHelp.getTableName(pClass), MiHelp.getTableId(pClass), id);
        return MiHelp.parsObj(map, pClass);
    }

    @Override
    public <P extends MiEntity> P selectOne(MiWrapper<P> miWrapper) {
        Map<?, ?> map = miMapper2._select_one_by_wrapper_(MiHelp.getSqlSelect(miWrapper), miWrapper.getTableName(), miWrapper.getSqlJoin(), miWrapper);
        return MiHelp.parsObj(map, miWrapper.tClass());
    }

    @Override
    public <P extends MiEntity> Map<String, Object> selectMap(MiWrapper<P> miWrapper) {
        return miMapper2._select_one_by_wrapper_(MiHelp.getSqlSelect(miWrapper), miWrapper.getTableName(), miWrapper.getSqlJoin(), miWrapper);
    }

    @Override
    public <P extends MiEntity> List<P> list(Class<P> pClass) {
        List<Map<String, Object>> maps = miMapper2._select_list_(MiHelp.getTableName(pClass));
        return MiHelp.parsArray(maps, pClass);
    }

    @Override
    public <P extends MiEntity> List<P> list(MiWrapper<P> miWrapper) {
        List<Map<String, Object>> maps = miMapper2._select_list_by_wrapper_(MiHelp.getSqlSelect(miWrapper), miWrapper.getTableName(), miWrapper.getSqlJoin(), miWrapper);
        return MiHelp.parsArray(maps, miWrapper.tClass());
    }

    @Override
    public <P extends MiEntity> List<P> listByIds(Class<P> pClass, List<? extends Serializable> idList) {
        MiWrapper<P> miWrapper = new MiWrapper<>(pClass);
        miWrapper.in(MiHelp.getTableId(pClass), idList);
        List<Map<String, Object>> maps = miMapper2._select_list_by_wrapper_(MiHelp.getSqlSelect(miWrapper), miWrapper.getTableName(), miWrapper.getSqlJoin(), miWrapper);
        return MiHelp.parsArray(maps, miWrapper.tClass());
    }

    @Override
    public <P extends MiEntity> List<P> listByMap(Class<P> pClass, Map<String, Object> columnMap) {
        List<Map> maps = miMapper2._select_list_by_map_(MiHelp.getTableName(pClass), columnMap);
        return MiHelp.parsArray(maps, pClass);
    }

    @Override
    public <P extends MiEntity> List<Map<String, Object>> listMaps(Class<P> pClass) {
        return miMapper2._select_list_(MiHelp.getTableName(pClass));
    }

    @Override
    public <P extends MiEntity> List<Map<String, Object>> listMaps(MiWrapper<P> miWrapper) {
        return miMapper2._select_list_by_wrapper_(MiHelp.getSqlSelect(miWrapper), miWrapper.getTableName(), miWrapper.getSqlJoin(), miWrapper);
    }

    @Override
    public <P extends MiEntity> List<Object> listObjs(Class<P> pClass) {
        return miMapper2._select_list_obj_(MiHelp.getTableName(pClass));
    }

    @Override
    public <P extends MiEntity> List<Object> listObjs(MiWrapper<P> miWrapper) {
        return miMapper2._select_list_obj_by_wrapper_(MiHelp.getSqlSelect(miWrapper), miWrapper.getTableName(), miWrapper.getSqlJoin(), miWrapper);
    }


    @Override
    public <P extends MiEntity> long count(Class<P> pClass) {
        return miMapper2._count_(MiHelp.getTableName(pClass));
    }

    @Override
    public <P extends MiEntity> long count(MiWrapper<P> miWrapper) {
        return miMapper2._count_by_wrapper_(miWrapper.getTableName(), miWrapper.getSqlJoin(), 1, miWrapper);
    }

    @Override
    public <P extends MiEntity> IPage<P> page(IPage<P> page, Class<P> pClass) {
        MiWrapper<P> miWrapper = new MiWrapper<P>(pClass);
        miWrapper.eq("1", 1);
        return page(page, miWrapper);
    }

    @Override
    public <P extends MiEntity> IPage<P> page(IPage<P> page, MiWrapper<P> miWrapper) {
        long current = page.getCurrent();
        long size = page.getSize();
        page.setTotal(count(miWrapper));
        long pages = (page.getTotal() + size - 1) / size;
        page.setPages(pages);
        List<Map<String, Object>> maps = miMapper2._page_by_wrapper_(MiHelp.getSqlSelect(miWrapper), miWrapper.getTableName(), miWrapper.getSqlJoin(), ((current - 1) * size), size, miWrapper);
        page.setRecords(MiHelp.parsArray(maps, miWrapper.tClass()));
        return page;
    }

    @Override
    public <P extends MiEntity> IPage<Map<String, Object>> pageMaps(IPage page, Class<P> pClass) {
        MiWrapper<P> miWrapper = new MiWrapper<>(pClass);
        miWrapper.eq("1", 1);
        return pageMaps(page, miWrapper);
    }

    @Override
    public <P extends MiEntity> IPage<Map<String, Object>> pageMaps(IPage page, MiWrapper<P> miWrapper) {
        long current = page.getCurrent();
        long size = page.getSize();
        page.setTotal(count(miWrapper));
        long pages = (page.getTotal() + size - 1) / size;
        page.setPages(pages);
        List<Map<String, Object>> maps = miMapper2._page_by_wrapper_(MiHelp.getSqlSelect(miWrapper), miWrapper.getTableName(), miWrapper.getSqlJoin(), ((current - 1) * size), size, miWrapper);
        page.setRecords(maps);
        return page;
    }

    @Override
    public long insert(String sqlString) {
        return miMapper2._insert_by_str_(sqlString);
    }

    @Override
    public long insert(String tableName, Map map) {
        return miMapper2._insert_by_map_(tableName, map);
    }

    @Override
    public long delete(String sqlString) {
        return miMapper2._delete_by_str_(sqlString);
    }

    @Override
    public long deleteById(String tableName, Serializable id) {
        return miMapper2._delete_by_id_(tableName, id);
    }

    @Override
    public long deleteByIds(String tableName, List<? extends Serializable> idList) {
        return miMapper2._delete_by_ids_(tableName, idList);

    }

    @Override
    public long update(String sqlString) {
        return miMapper2._update_by_str_(sqlString);
    }

    @Override
    public long updateById(String tableName, Map map, Serializable id) {
        return miMapper2._update_by_map_id_(tableName, map, id);
    }

    @Override
    public long updateByIds(String tableName, Map map, List<Serializable> ids) {
        return miMapper2._update_by_map_ids_(tableName, map, ids);
    }

    @Override
    public Map<String, Object> selectOne(String sqlString) {
        return miMapper2._select_one_by_str_(sqlString);
    }

    @Override
    public List<Map<String, Object>> list(String sqlString) {
        return miMapper2._select_list_by_str_(sqlString);
    }

    @Override
    public List<Object> listObjs(String sqlString) {
        return miMapper2._select_list_obj_by_str_(sqlString);
    }

    @Override
    public long count(String sqlString) {
        return miMapper2._count_by_str_(sqlString);
    }

    @Override
    public IPage<Map<String, Object>> page(IPage<Map<String, Object>> page, String sqlString) {
        return null;
    }

}
